﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

using SmlEngine.UI.Input;

namespace SmlEngine.UI.Managers
{
    public sealed class InputManager : GameComponent
    {
        public InputState Current { get; set; }
        public InputState Previous { get; set; }

        public int MouseX { get { return Current.MouseState.X; } }
        public int MouseY { get { return Current.MouseState.Y; } }

        public InputManager(Game game)
            : base(game)
        {
            Current = new InputState(null, null, null);
        }

        public override void Update(GameTime gameTime)
        {
            Previous = new InputState(Current.KeyboardState, Current.MouseState, Current.GamePadStates);
            Current = new InputState(null, null, null);

            base.Update(gameTime);
        }

        /// <summary>
        /// Indicates whether a specified key is newly pressed in the current frame.
        /// </summary>
        /// <param name="key">The key to check for a new press.</param>
        public bool IsNewKeyPress(Keys key)
        {
            return Current.KeyboardState.IsKeyDown(key) &&
                   Previous.KeyboardState.IsKeyUp(key);
        }

        /// <summary>
        /// Indicates whether a specified key is newly released in the current frame.
        /// </summary>
        /// <param name="key">The key to check for a new release.</param>
        public bool IsNewKeyRelease(Keys key)
        {
            return Current.KeyboardState.IsKeyUp(key) &&
                   Previous.KeyboardState.IsKeyDown(key);
        }

        /// <summary>
        /// Indicates whether a specified key is newly toggled in the current frame.
        /// </summary>
        /// <param name="key">The key to check for a new toggle.</param>
        public bool IsToggleKeyPress(Keys key)
        {
            return Current.KeyboardState.IsKeyDown(key) !=
                   Previous.KeyboardState.IsKeyDown(key);
        }

        /// <summary>
        /// Indicates whether the left mouse button is newly pressed in the current frame.
        /// </summary>
        public bool IsNewLeftMouseClick()
        {
            return Current.MouseState.LeftButton == ButtonState.Pressed &&
                   Previous.MouseState.LeftButton != ButtonState.Pressed;
        }

        /// <summary>
        /// Indicates whether the right mouse button is newly pressed in the current frame.
        /// </summary>
        public bool IsNewRightMouseClick()
        {
            return Current.MouseState.RightButton == ButtonState.Pressed &&
                   Previous.MouseState.RightButton != ButtonState.Pressed;
        }

        /// <summary>
        /// Indicates whether a specified button is newly pressed in the current frame.
        /// </summary>
        /// <param name="button">The button to check for a new press.</param>
        public bool IsNewGamePadButtonPress(Buttons button)
        {
            return IsNewGamePadButtonPress(button, PlayerIndex.One);
        }

        /// <summary>
        /// Indicates whether a specified button is newly released in the current frame.
        /// </summary>
        /// <param name="button">The button to check for a new release.</param>
        public bool IsNewGamePadButtonRelease(Buttons button)
        {
            return IsNewGamePadButtonRelease(button, PlayerIndex.One);
        }

        /// <summary>
        /// Indicates whether a specified button is newly toggled in the current frame.
        /// </summary>
        /// <param name="button">The button to check for a new toggle.</param>
        public bool IsGamePadToggleButtonPress(Buttons button)
        {
            return IsGamePadToggleButtonPress(button, PlayerIndex.One);
        }

        /// <summary>
        /// Indicates whether a specified button is newly pressed in the current frame.
        /// </summary>
        /// <param name="button">The button to check for a new press.</param>
        public bool IsNewGamePadButtonPress(Buttons button, PlayerIndex playerIndex)
        {
            return Current.GamePadStates[playerIndex].IsButtonDown(button) &&
                   Previous.GamePadStates[playerIndex].IsButtonUp(button);
        }

        /// <summary>
        /// Indicates whether a specified button is newly released in the current frame.
        /// </summary>
        /// <param name="button">The button to check for a new release.</param>
        public bool IsNewGamePadButtonRelease(Buttons button, PlayerIndex playerIndex)
        {
            return Current.GamePadStates[playerIndex].IsButtonUp(button) &&
                   Previous.GamePadStates[playerIndex].IsButtonDown(button);
        }

        /// <summary>
        /// Indicates whether a specified button is newly toggled in the current frame.
        /// </summary>
        /// <param name="button">The button to check for a new toggle.</param>
        public bool IsGamePadToggleButtonPress(Buttons button, PlayerIndex playerIndex)
        {
            return Current.GamePadStates[playerIndex].IsButtonDown(button) !=
                   Previous.GamePadStates[playerIndex].IsButtonDown(button);
        }

        /// <summary>
        /// Indicates whether a specified KeyMap is newly pressed in the current frame.
        /// </summary>
        /// <param name="key">The KeyMap to check for a new press.</param>
        public bool IsNewKeyMapPress(KeyMap key)
        {
            return Current.IsKeyMapDown(key) &&
                   Previous.IsKeyMapUp(key);
        }

        /// <summary>
        /// Indicates whether a specified KeyMap is newly released in the current frame.
        /// </summary>
        /// <param name="key">The KeyMap to check for a new release.</param>
        public bool IsNewKeyMapRelease(KeyMap key)
        {
            return Current.IsKeyMapUp(key) &&
                   Previous.IsKeyMapDown(key);
        }

        /// <summary>
        /// Indicates whether a specified KeyMap is newly toggled in the current frame.
        /// </summary>
        /// <param name="key">The KeyMap to check for a new toggle.</param>
        public bool IsToggleKeyPress(KeyMap key)
        {
            return Current.IsKeyMapDown(key) !=
                   Previous.IsKeyMapDown(key);
        }
    }
}
